home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / userconf / users.c < prev   
C/C++ Source or Header  |  1996-07-20  |  8KB  |  401 lines

  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <pwd.h>
  4. #include <sys/stat.h>
  5. #include "../xconf/xconf.h"
  6. #include "../paths.h"
  7. #include "internal.h"
  8. #include "userconf.h"
  9. #include "userconf.m"
  10.  
  11. /* #Specification: userconf / etc/passwd
  12.     /etc/passwd is the user database. Its permission flags are
  13.     always set to 0644 when rewritten.
  14. */
  15. #define ETC_PTMP    "/etc/ptmp"
  16. static USERCONF_HELP_FILE help_users ("users");
  17. static CONFIG_FILE f_passwd (ETC_PASSWD,help_users,CONFIGF_MANAGED
  18.     ,"root","root",0644);
  19.  
  20. PUBLIC USERS::USERS()
  21. {
  22.     /* #Specification: /etc/passwd / strategy
  23.         /etc/passwd is read "by hand" instead of using getpwent() to avoid
  24.         getting all those NIS entries. This is done when editing local
  25.         user account.
  26.     */
  27.     FILE *fin = f_passwd.fopen ("r");
  28.     if (fin != NULL){
  29.         char line[1000];
  30.         while (fgets(line,sizeof(line)-1,fin)!=NULL){
  31.             strip_end (line);
  32.             if (line[0] != '\0'){
  33.                 add (new USER(line));
  34.             }
  35.         }
  36.         fclose (fin);
  37.     }
  38.     shadows = NULL;
  39.     if (shadow_exist()) shadows = new SHADOWS;
  40.     rstmodified();
  41. }
  42.  
  43. PUBLIC USERS::~USERS()
  44. {
  45.     delete shadows;
  46. }
  47. /*
  48.     Get one USER specification of the table or NULL
  49. */
  50. PUBLIC USER *USERS::getitem(int no)
  51. {
  52.     return (USER*)ARRAY::getitem(no);
  53. }
  54. /*
  55.     Get one USER specification of the table or NULL from his login name
  56. */
  57. PUBLIC USER *USERS::getitem(const char *name)
  58. {
  59.     USER *ret = NULL;
  60.     int nbu = getnb();
  61.     for (int i=0; i<nbu; i++){
  62.          USER *usr = getitem(i);
  63.         if (strcmp(usr->getname(),name)==0){
  64.             ret = usr;
  65.             break;
  66.         }
  67.     }
  68.     return ret;
  69. }
  70. /*
  71.     Get one SHADOW specification of the table or NULL from his login name
  72. */
  73. PUBLIC SHADOW *USERS::getshadow(USER *usr)
  74. {
  75.     SHADOW *ret = NULL;
  76.     if (shadows != NULL) ret = shadows->getitem(usr->getname());
  77.     return ret;
  78. }
  79. PUBLIC void USERS::addshadow (SHADOW *shadow)
  80. {
  81.     shadows->add (shadow);
  82. }
  83. /*
  84.     Get one USER specification of the table or NULL from his UID
  85. */
  86. PUBLIC USER *USERS::getfromuid(int uid)
  87. {
  88.     USER *ret = NULL;
  89.     int nbu = getnb();
  90.     for (int i=0; i<nbu; i++){
  91.          USER *usr = getitem(i);
  92.         if (usr->getuid() == uid){
  93.             ret = usr;
  94.             break;
  95.         }
  96.     }
  97.     return ret;
  98. }
  99. /*
  100.     Get one unused User ID base of the group name.
  101.     This function try to organise user id group wize, allocating 500
  102.     entry per group.
  103. */
  104. PUBLIC int USERS::getnewuid(int gid)
  105. {
  106.     /* #Specification: userconf / automatic allocaion of uid
  107.         We multiply gid by 500. From there we search in all
  108.         user id and allocate the first uid in the range.
  109.  
  110.         We don't allocate into holes (unused uid between used one)
  111.         to avoid uid reuse (and a security hole).
  112.     */
  113.     int base = gid * 500;
  114.     int maxu = base + 500;
  115.     int ret = base;
  116.     int nbu = getnb();
  117.     for (int i=0; i<nbu; i++){
  118.          USER *usr = getitem(i);
  119.         int uid = usr->getuid();
  120.         if (uid >= base && uid < maxu){
  121.             if (uid >= ret) ret = uid + 1;
  122.         }
  123.     }
  124.     return ret;    
  125. }
  126. /*
  127.     Write the /etc/passwd file with proper locking
  128. */
  129. PUBLIC int USERS::write()
  130. {
  131.     int ret = -1;
  132.     sortbygid();
  133.     FILE *fout = f_passwd.fopen (ETC_PTMP,"w");
  134.     if (fout != NULL){
  135.         int nbu = getnb();
  136.         for (int i=0; i<nbu; i++){
  137.             getitem(i)->write(fout);
  138.         }
  139.         fclose(fout);
  140.         unlink(ETC_PASSWD ".OLD");
  141.         link(ETC_PASSWD, ETC_PASSWD ".OLD");
  142.         unlink(ETC_PASSWD);
  143.         link(ETC_PTMP, ETC_PASSWD);
  144.         unlink(ETC_PTMP);
  145.         if (shadows != NULL) shadows->write();
  146.         ret = 0;
  147.     }
  148.     return ret;
  149. }
  150.  
  151. /*
  152.     Select one user from the list.
  153.     May return NULL if no valid selection was done (escape). See code.
  154. */
  155. PUBLIC USER *USERS::select(
  156.     USER *like,    // Used to select which user to pick.
  157.             // the function USER::islike() is called for
  158.             // each.
  159.     int may_add,    // Set the delete and add button
  160.     MENU_STATUS &code,
  161.     int &choice)    // Will contain the selection. Not so useful
  162.             // but help for the reentrancy of the list
  163.             // (It reedit on the last item selected).
  164. {
  165.     int nbu = getnb();
  166.     sortbyname();
  167.     /* #Specification: userconf / user account / root bin ...
  168.         Some special account are simply left out of the configuration
  169.         menu. These account are never edited. They make the list larger
  170.         for no reason.
  171.  
  172.         Also account with special shells are not shown. This include
  173.         accounts like uucp and slip. Theu are show in a separate menu.
  174.  
  175.         The same functionnality is used to edit those accounts, but
  176.         the editition is trigerred from different menus.
  177.     */
  178.     DIALOG dia;
  179.     for (int i=0; i<nbu; i++){
  180.         USER *usr = getitem(i);
  181.         if (usr->is_like(like)){
  182.             dia.new_menuitem (usr->getname(),usr->getgecos());
  183.         }
  184.     }
  185.     if (may_add){
  186.         dia.addwhat (MSG_R(I_TOADD));
  187.     }
  188.     code = dia.editmenu (MSG_U(T_USERACCT,"Users accounts")
  189.         ,may_add
  190.             ? MSG_U(I_CANEDIT,"You can edit, add, or delete users")
  191.             : MSG_U(I_SELECT,"You must select one of those users")
  192.         ,help_users
  193.         ,choice,0);
  194.     USER *ret = NULL;
  195.     // Locate the selected user in the list, given that not all
  196.     // user where displayed.
  197.     int nou = 0;
  198.     for (int j=0; j<nbu; j++){
  199.         USER *usr = getitem(j);
  200.         if (usr->is_like(like)){
  201.             if (nou == choice){
  202.                 ret = usr;
  203.                 break;
  204.             }
  205.             nou++;
  206.         }
  207.     }
  208.     return ret;
  209. }
  210.  
  211. /*
  212.     Add one new user
  213.     Return -1 if the user was not added.
  214. */
  215. PUBLIC int USERS::addone (
  216.     USER *special,
  217.     const char *name,    // Proposed login name
  218.     GROUPS &groups)
  219. {
  220.     int ret = -1;
  221.     USER *user = new USER;
  222.     user->setlike (special);
  223.     user->setname (name);
  224.     ret = user->edit(*this,groups,1);
  225.     if (ret==0){
  226.         add (user);
  227.         write ();
  228.     }else{
  229.         delete user;
  230.     }
  231.     return ret;
  232. }
  233.  
  234. /*
  235.     General edition (addition/deletion/correction) of /etc/passwd
  236. */
  237. PUBLIC int USERS::edit(
  238.     USER *special)        // Template for user creation
  239.                 // and selection.
  240. {
  241.     int ret = -1;
  242.     int choice = 0;
  243.     GROUPS groups;
  244.     while (1){
  245.         MENU_STATUS code;
  246.         USER *usr = select (special,1,code,choice);
  247.         if (code == MENU_ESCAPE || code == MENU_QUIT){
  248.             break;
  249.         }else if (code == MENU_OK){
  250.             if (usr != NULL){
  251.                 int status = usr->edit(*this,groups,0);
  252.                 if (status != -1){
  253.                     if (status == 1) remove_del (usr);
  254.                     write();
  255.                     ret = 0;
  256.                 }
  257.             }
  258.         }else if (perm_rootaccess(MSG_U(P_USERDB
  259.                 ,"to maintain the user database"))){
  260.             if (code == MENU_ADD){
  261.                 addone (special,NULL,groups);
  262.             }
  263.         }
  264.     }
  265.     return ret;
  266. }
  267. static int cmpbyname (const ARRAY_OBJ *o1, const ARRAY_OBJ *o2)
  268. {
  269.     USER *g1 = (USER*) o1;
  270.     USER *g2 = (USER*) o2;
  271.     return strcmp(g1->getname(),g2->getname());
  272. }
  273. /*
  274.     Sort the array of group by name
  275. */
  276. PUBLIC void USERS::sortbyname()
  277. {
  278.     sort (cmpbyname);
  279. }
  280. static int cmpbygid (const ARRAY_OBJ *o1, const ARRAY_OBJ *o2)
  281. {
  282.     USER *g1 = (USER*) o1;
  283.     USER *g2 = (USER*) o2;
  284.     int ret = g1->getgid() - g2->getgid();
  285.     if (ret == 0){
  286.         ret = strcmp(g1->getname(),g2->getname());
  287.     }
  288.     return ret;
  289. }
  290. /*
  291.     Sort the array of group by gid, and name
  292. */
  293. PUBLIC void USERS::sortbygid()
  294. {
  295.     sort (cmpbygid);
  296. }
  297. /*
  298.     Edition of users password.
  299.     Return 0 if at least one change was done.
  300. */
  301. PUBLIC int USERS::editpass(
  302.     USER *special)        // see USERS::select()
  303. {
  304.     int ret = -1;
  305.     int choice = 0;
  306.     while (1){
  307.         MENU_STATUS code;
  308.         USER *usr = select (special,0,code,choice);
  309.         if (code == MENU_ESCAPE || code == MENU_QUIT){
  310.             break;
  311.         }else{
  312.             SHADOW *shadow = getshadow (usr);
  313.             if (usr->editpass(1,shadow) != -1){
  314.                 write();
  315.                 ret = 0;
  316.             }
  317.         }
  318.     }
  319.     return ret;
  320. }
  321.  
  322. /*
  323.     General edition of users account and special account
  324.     See USERS::edit()
  325. */
  326. void users_edit(
  327.     USER *special)    // Template for a special account.
  328.                     // Or NULL.
  329. {
  330.     USERS users;
  331.     users.edit(special);
  332. }
  333.  
  334. /*
  335.     Add one new special user
  336. */
  337. void users_addone(
  338.     const char *name,
  339.     const char *group)    // Which group to use or NULL.
  340. {
  341.     if (perm_rootaccess(MSG_R(P_USERDB))){
  342.         USER *special;
  343.         if (special_init (group,special) != -1){
  344.             USERS users;
  345.             GROUPS groups;
  346.             users.addone(special,name,groups);
  347.         }
  348.         delete special;    
  349.     }
  350. }
  351.  
  352. /*
  353.     Return != 0 if a user account exist.
  354. */
  355. int user_exist (const char *name)
  356. {
  357.     return getpwnam(name)!=NULL;
  358. }
  359.     
  360.  
  361. /*
  362.     Edit one user spec.
  363.     If the user does not exist, ask if we want to create it.
  364. */
  365. void users_editone(
  366.     const char *name,
  367.     const char *group)    // Group to use (or NULL) if the user
  368.                         // is created
  369. {
  370.     USERS users;
  371.     if (perm_rootaccess(MSG_R(P_USERDB))){
  372.         USER *user = users.getitem(name);
  373.         if (user == NULL){
  374.             char buf[300];
  375.             sprintf (buf,MSG_U(I_USERCREATE,"User account %s does not exist\n"
  376.                  "Do you want to create it"),name);
  377.             if (xconf_yesno(MSG_U(Q_USERCREATE,"Account creation")
  378.                 ,buf,help_users)==MENU_YES){
  379.                 users_addone    (name,group);
  380.             }
  381.         }else{
  382.             GROUPS groups;
  383.             if (user->edit(users,groups,0)!=-1) users.write();
  384.         }
  385.     }
  386. }
  387.  
  388.  
  389. #ifdef TEST
  390.  
  391. int main (int argc, char *argv[])
  392. {
  393.     users_edit(NULL);
  394.     users_edit("-");
  395.     users_edit("/usr/lib/uucp/uucico");
  396. }
  397.  
  398. #endif
  399.  
  400.  
  401.